package huadi.android.sudoku;

import android.app.Dialog;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.FontMetrics;
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.AnimationUtils;

/**
 * Puzzle view, main interface of the game.
 * 
 * @author huadi
 */
public class PuzzleView extends View {
	public static final String LOG_TAG = "PuzzleView";

	private GameActivity game;
	/** the width of every small rect. */
	private float width;
	/** the height of every small rect. */
	private float height;
	/** the selected rect coordinate */
	private int selX = 0;
	/** the selected rect coordinate */
	private int selY = 0;
	private final Rect selRect = new Rect();
	private int color = getResources().getColor(R.color.puzzle_selected);

	public PuzzleView(Context context) {
		super(context);
		this.game = (GameActivity) context;
		setFocusable(true);
		setFocusableInTouchMode(true);
	}

	@Override
	protected void onSizeChanged(int w, int h, int oldw, int oldh) {
		this.width = w / 9f;
		this.height = h / 9f;
		setRect(selX, selY, selRect);
		super.onSizeChanged(w, h, oldw, oldh);
	}

	@Override
	protected void onDraw(Canvas canvas) {
		// Draw the background
		Paint background = new Paint();
		background.setColor(getResources().getColor(R.color.puzzle_background));
		canvas.drawRect(0, 0, getWidth(), getHeight(), background);
		// Draw the board
		Paint dark = new Paint();
		dark.setColor(getResources().getColor(R.color.puzzle_dark));
		Paint hilite = new Paint();
		hilite.setColor(getResources().getColor(R.color.puzzle_hilite));
		Paint light = new Paint();
		light.setColor(getResources().getColor(R.color.puzzle_light));
		for (int i = 1; i < 9; i++) {
			if (i % 3 == 0) {
				canvas.drawLine(i * this.width, 0, i * this.width, getHeight(),
						dark);
				canvas.drawLine(i * this.width + 1, 0, i * this.width + 1,
						getHeight(), hilite);
				canvas.drawLine(0, i * this.height, getWidth(),
						i * this.height, dark);
				canvas.drawLine(0, i * this.height + 1, getWidth(), i
						* this.height + 1, hilite);
			} else {
				canvas.drawLine(i * this.width, 0, i * this.width, getHeight(),
						light);
				canvas.drawLine(i * this.width + 1, 0, i * this.width + 1,
						getHeight(), hilite);
				canvas.drawLine(0, i * this.height, getWidth(),
						i * this.height, light);
				canvas.drawLine(0, i * this.height + 1, getWidth(), i
						* this.height + 1, hilite);
			}
		}

		// Draw the numbers
		Paint foreground = new Paint(Paint.ANTI_ALIAS_FLAG);
		foreground.setTextSize(height * 0.75f);
		foreground.setColor(getResources().getColor(R.color.puzzle_foreground));
		foreground.setStyle(Style.FILL);
		foreground.setTextScaleX(width / height);
		foreground.setTextAlign(Paint.Align.CENTER);
		// Draw the number in the center of the tile
		FontMetrics fm = foreground.getFontMetrics();
		// Centering in X
		float x = width / 2;
		// Centering in Y
		float y = height / 2 - (fm.ascent + fm.descent) / 2;
		for (int i = 0; i < 9; i++) {
			for (int j = 0; j < 9; j++) {
				if (!(this.game.getTile(i, j) == 0)) {
					canvas.drawText(this.game.getTileString(i, j), i * width
							+ x, j * height + y, foreground);
				}
			}
		}
		// Draw the hints
		Paint hint = new Paint();
		int c[] = { getResources().getColor(R.color.puzzle_hint_0),
				getResources().getColor(R.color.puzzle_hint_1),
				getResources().getColor(R.color.puzzle_hint_2) };
		Rect r = new Rect();
		for (int i = 0; i < 9; i++) {
			for (int j = 0; j < 9; j++) {
				int movesLeft = 9/* - game.getUsedTiles(i, j).length */;
				if (movesLeft < c.length) {
					this.setRect(i, j, r);
					hint.setColor(c[movesLeft]);
					canvas.drawRect(r, hint);
				}
			}
		}
		// Draw the selection
		Paint select = new Paint();
		select.setColor(this.color);
		canvas.drawRect(selRect, select);
	}

	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		switch (keyCode) {
		case KeyEvent.KEYCODE_SPACE:
			Dialog keypad = new KeypadDialog(this.game, new int[] {}, this);
			keypad.show();
			break;
		case KeyEvent.KEYCODE_DPAD_UP:
			select(selX, selY - 1);
			break;
		case KeyEvent.KEYCODE_DPAD_DOWN:
			select(selX, selY + 1);
			break;
		case KeyEvent.KEYCODE_DPAD_LEFT:
			select(selX - 1, selY);
			break;
		case KeyEvent.KEYCODE_DPAD_RIGHT:
			select(selX + 1, selY);
			break;
		case KeyEvent.KEYCODE_0:
			Log.d(LOG_TAG, "key 0 pressed");
			setSelectedTile(0);
			break;
		case KeyEvent.KEYCODE_1:
			Log.d(LOG_TAG, "key 1 pressed");
			setSelectedTile(1);
			break;
		case KeyEvent.KEYCODE_2:
			Log.d(LOG_TAG, "key 2 pressed");
			setSelectedTile(2);
			break;
		case KeyEvent.KEYCODE_3:
			Log.d(LOG_TAG, "key 3 pressed");
			setSelectedTile(3);
			break;
		case KeyEvent.KEYCODE_4:
			Log.d(LOG_TAG, "key 4 pressed");
			setSelectedTile(4);
			break;
		case KeyEvent.KEYCODE_5:
			Log.d(LOG_TAG, "key 5 pressed");
			setSelectedTile(5);
			break;
		case KeyEvent.KEYCODE_6:
			Log.d(LOG_TAG, "key 6 pressed");
			setSelectedTile(6);
			break;
		case KeyEvent.KEYCODE_7:
			Log.d(LOG_TAG, "key 7 pressed");
			setSelectedTile(7);
			break;
		case KeyEvent.KEYCODE_8:
			Log.d(LOG_TAG, "key 8 pressed");
			setSelectedTile(8);
			break;
		default:
			return super.onKeyDown(keyCode, event);
		}
		return true;
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			this.color = getResources().getColor(R.color.puzzle_selected_down);
			select((int) (event.getX() / width), (int) (event.getY() / height));
			break;
		case MotionEvent.ACTION_UP:
			// draw the rect background
			this.color = getResources().getColor(R.color.puzzle_selected);
			select((int) (event.getX() / width), (int) (event.getY() / height));
			// game.showKeypadOrError(selX, selY);
			Log.d(LOG_TAG, "onTouchEvent: x = " + selX + ", y = " + selY);
			break;
		case MotionEvent.ACTION_MOVE:
			Log.i(LOG_TAG, "movemovemove");
		default:
			return super.onTouchEvent(event);
		}
		return true;
	}

	private void select(int x, int y) {
		invalidate(selRect);
		selX = Math.min(Math.max(x, 0), 8);
		selY = Math.min(Math.max(y, 0), 8);
		setRect(selX, selY, selRect);
		invalidate(selRect);
	}

	/**
	 * Set Rect
	 * 
	 * @param selX
	 * @param selY
	 * @param selRect
	 */
	private void setRect(int selX, int selY, Rect selRect) {
		selRect.set((int) (selX * width), (int) (selY * height), (int) (selX
				* width + width), (int) (selY * height + height));
	}

	void setSelectedTile(int tile) {
		this.game.setTile(selX, selY, tile);
		invalidate(selRect);
		// invalid number shake the screen
		// if (false)
		startAnimation(AnimationUtils.loadAnimation(game, R.anim.shake));
		// if (game.setTileIfValid(selX, selY, tile)) {
		// // mark all the screen to invalidate
		// // may cause redraw the whole screen
		// invalidate();
		// } else {
		// Log.d(LOG_TAG, "set selected tile an invalid value: " + tile);
		// }
	}
}
